package com.aqie.rabbit.service.Impl;

import com.aqie.rabbit.bean.api.base.CodeMsg;
import com.aqie.rabbit.bean.api.base.PushModel;
import com.aqie.rabbit.bean.card.GroupMemberCard;
import com.aqie.rabbit.bean.card.MessageCard;
import com.aqie.rabbit.bean.card.UserCard;
import com.aqie.rabbit.bean.db.*;
import com.aqie.rabbit.exception.GlobalException;
import com.aqie.rabbit.service.*;
import com.aqie.rabbit.utils.PushDispatcher;
import com.aqie.rabbit.utils.TextUtil;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class PushServiceImpl implements IPushService {
    @Autowired
    private IUserService userService;

    @Autowired
    private IPushHistoryService pushHistoryService;

    @Autowired
    private IGroupService groupService;

    @Autowired
    private IGroupMemberService groupMemberService;

    @Override
    @Transactional
    public void pushNewMessage(User sender, Message message) {
        if (sender == null || message == null){
            throw new GlobalException(CodeMsg.MESSAGE_AND_SENDER_IS_NULL_ERROR);
        }
        // 消息卡片用于发送
        MessageCard card = new MessageCard(message);
        // 要推送的字符串
        String entity = TextUtil.toJson(card);

        // 发送者
        PushDispatcher dispatcher = new PushDispatcher();

        // 给朋友发送消息
        if (message.getGroup() == null
                && Strings.isNullOrEmpty(message.getGroupId())) {
            User receiver = userService.findById(message.getReceiverId());
            if (receiver == null){
                throw new GlobalException(CodeMsg.MESSAGE_RECEIVER_ID_IS_NULL_ERROR);
            }

            // 历史记录表字段建立
            PushHistory history = new PushHistory();
            history.setEntityType(PushModel.ENTITY_TYPE_MESSAGE);
            history.setEntity(entity);
            history.setReceiver(receiver);
            // 接收者当前的设备推送Id
            history.setReceiverPushId(receiver.getPushId());


            // 推送真实的model
            PushModel pushModel = new PushModel();
            // 每一条历史记录都是独立的，可以单独的发送
            pushModel.add(history.getEntityType(), history.getEntity());
            // 把需要发送的数据，丢给发送者进行发送
            dispatcher.add(receiver, pushModel);

            // 保存历史记录到数据库
            pushHistoryService.save(history);
        }else{      // 群内发送消息
            Group group = message.getGroup();
            if (group == null){
                group = groupService.findById(message.getGroupId());
            }
            if (group == null){
                throw new GlobalException(CodeMsg.GROUP_NOT_FOUND_ERROR);
            }

            // 1. 给群成员发送消息
            Set<GroupMember> members = groupMemberService.getMembers(group);
            if (members == null || members.size() == 0)
                throw new GlobalException(CodeMsg.GROUP_IS_EMPTY_ERROR);

            // 2. 过滤自己
            members = members.stream().filter(groupMember -> !groupMember.getUserId()
                .equalsIgnoreCase(sender.getId())).collect(Collectors.toSet());
            if (members.size() == 0)
                throw new GlobalException(CodeMsg.GROUP_ONLY_HAVE_YOURSELF_ERROR);

            // 3.一个历史记录列表
            List<PushHistory> histories = new ArrayList<>();
            addGroupMembersPushModel(dispatcher, // 推送的发送者
                    histories, // 数据库要存储的列表
                    members,    // 所有的成员
                    entity, // 要发送的数据
                    PushModel.ENTITY_TYPE_MESSAGE); // 发送的类型
            pushHistoryService.saveAll(histories);
        }

        // 发送者进行真实提交
        dispatcher.submit();
    }

    /**
     * 给群成员构建一个消息，
     * 把消息存储到数据库的历史记录中，每个人，每条消息都是一个记录
     */
    private void addGroupMembersPushModel(PushDispatcher dispatcher, List<PushHistory> histories,
                                          Set<GroupMember> members,
                                          String entity, int entityTypeMessage) {

        for (GroupMember member : members){
            User receiver = member.getUser();
            if (receiver == null){
                throw new GlobalException(CodeMsg.GROUP_MEMBER_HAVE_NOT_USER_ERROR);
            }

            // 历史记录字段
            PushHistory history = new PushHistory();
            history.setEntityType(entityTypeMessage);
            history.setEntity(entity);
            history.setReceiver(receiver);
            history.setReceiverPushId(receiver.getPushId());
            histories.add(history);

            // 构建一个消息Model
            PushModel pushModel = new PushModel();
            pushModel.add(history.getEntityType(), history.getEntity());

            // 添加到发送者的数据集中
            dispatcher.add(receiver, pushModel);
        }
    }

    @Override
    public void pushJoinGroup(Set<GroupMember> members) {
        // 发送者
        PushDispatcher dispatcher = new PushDispatcher();

        // 一个历史记录列表
        List<PushHistory> histories = new ArrayList<>();

        for (GroupMember member : members) {
            User receiver = member.getUser();
            if (receiver == null)
                return;

            // 每个成员的信息卡片
            GroupMemberCard memberCard = new GroupMemberCard(member);
            String entity = TextUtil.toJson(memberCard);

            // 历史记录表字段建立
            PushHistory history = new PushHistory();
            // 你被添加到群的类型
            history.setEntityType(PushModel.ENTITY_TYPE_ADD_GROUP);
            history.setEntity(entity);
            history.setReceiver(receiver);
            history.setReceiverPushId(receiver.getPushId());
            histories.add(history);

            // 构建一个消息Model
            PushModel pushModel = new PushModel()
                    .add(history.getEntityType(), history.getEntity());

            // 添加到发送者的数据集中
            dispatcher.add(receiver, pushModel);
            histories.add(history);
        }

        // 保存到数据库的操作
        pushHistoryService.saveAll(histories);

        // 提交发送
        dispatcher.submit();
    }

    @Override
    public void pushGroupMemberAdd(Set<GroupMember> oldMembers, List<GroupMemberCard> insertCards) {
        // 发送者
        PushDispatcher dispatcher = new PushDispatcher();

        // 一个历史记录列表
        List<PushHistory> histories = new ArrayList<>();

        // 当前新增的用户的集合的Json字符串
        String entity = TextUtil.toJson(insertCards);

        // 进行循环添加，给oldMembers每一个老的用户构建一个消息，消息的内容为新增的用户的集合
        // 通知的类型是：群成员添加了的类型
        addGroupMembersPushModel(dispatcher, histories, oldMembers,
                entity, PushModel.ENTITY_TYPE_ADD_GROUP_MEMBERS);

        // 保存到数据库的操作
        pushHistoryService.saveAll(histories);

        // 提交发送
        dispatcher.submit();
    }

    @Override
    public void pushLogout(User receiver, String pushId) {
        // 历史记录表字段建立
        PushHistory history = new PushHistory();
        // 你被添加到群的类型
        history.setEntityType(PushModel.ENTITY_TYPE_LOGOUT);
        history.setEntity("Account logout!!!");
        history.setReceiver(receiver);
        history.setReceiverPushId(pushId);
        // 保存到历史记录表
        pushHistoryService.save(history);

        // 发送者
        PushDispatcher dispatcher = new PushDispatcher();
        // 具体推送的内容
        PushModel pushModel = new PushModel()
                .add(history.getEntityType(), history.getEntity());

        // 添加并提交到第三方推送
        dispatcher.add(receiver, pushModel);
        dispatcher.submit();
    }

    @Override
    public void pushFollow(User receiver, UserCard userCard) {
        // 一定是相互关注了
        userCard.setFollow(true);
        String entity = TextUtil.toJson(userCard);

        // 历史记录表字段建立
        PushHistory history = new PushHistory();
        // 你被添加到群的类型
        history.setEntityType(PushModel.ENTITY_TYPE_ADD_FRIEND);
        history.setEntity(entity);
        history.setReceiver(receiver);
        history.setReceiverPushId(receiver.getPushId());
        // 保存到历史记录表
        pushHistoryService.save(history);

        // 推送
        PushDispatcher dispatcher = new PushDispatcher();
        PushModel pushModel = new PushModel()
                .add(history.getEntityType(), history.getEntity());
        dispatcher.add(receiver, pushModel);
        dispatcher.submit();
    }
}
